package com.tianji.learning.handler;

import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.learning.constant.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.service.PointsBoardSeasonService;
import com.tianji.learning.service.PointsBoardService;
import com.tianji.learning.utils.TableInfoContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

import static com.tianji.learning.constant.LearningConstants.POINTS_BOARD_TABLE_PREFIX;

/**
 * @author : Cammy.Wu
 * Description : 
 */

@Component
@RequiredArgsConstructor
public class PointsBoardPersistentHandler {

    private final PointsBoardSeasonService seasonService;

    private final PointsBoardService pointsBoardService;

    private final StringRedisTemplate redisTemplate;

    /**
     * 每月1号凌晨3点执行，创建上一赛季的积分排行榜表
     */
//    @Scheduled(cron = "0 0 3 1 * ?") // 每月1号，凌晨3点执行
    @XxlJob("createTableJob")
    public void createPointsBoardTableOfLastSeason() {
        // 1.获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        // 2.查询上月对应赛季id
        // 这里调用 seasonService 的 querySeasonByTime 方法，根据上月时间查询对应的赛季 ID
        Integer season = seasonService.querySeasonByTime(time);
        if (season != null) {
            // 这里的注释有误，应该是赛季存在才继续执行，若赛季不存在则直接返回
            // 若 season 不为 null，说明赛季存在，后续可以进行创建表的操作
            // 若这里逻辑是判断赛季不存在返回，应改为 if(season == null)
            return;
        }
        // 3.创建表
        // 调用 pointsBoardService 的 createPointsBoardTableBySeason 方法，根据赛季 ID 创建积分排行榜表
        pointsBoardService.createPointsBoardTableBySeason(season);
    }

    @XxlJob("savePointsBoard2DB")  // 声明XXL-JOB任务，任务名为"savePointsBoard2DB"
    public void savePointsBoard2DB() {
        // ==================== 阶段1：准备数据 ====================
        // 1. 时间计算：获取上个月的时间（用于处理上月数据）
        LocalDateTime time = LocalDateTime.now().minusMonths(1);

        // 2. 动态表名处理
        // 2.1 查询赛季信息（根据时间获取对应赛季ID）
        Integer season = seasonService.querySeasonByTime(time);
        // 2.2 存储动态表名到线程上下文（格式示例：points_board_202402）
        TableInfoContext.setInfo(POINTS_BOARD_TABLE_PREFIX + season);

        // ==================== 阶段2：数据处理 ====================
        // 3. Redis数据分页查询
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX
                + time.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER); // 构建Redis键，如：board:202402

        int index = XxlJobHelper.getShardIndex();
        int total = XxlJobHelper.getShardTotal();
        int pageNo = index + 1; // 起始页，就是分片序号+1
        int pageSize = 10;

        // 分页循环处理（类似流水线作业）
        while (true) {
            // 3.1 分页读取Redis榜单数据
            List<PointsBoard> boardList = pointsBoardService.queryCurrentBoardList(key, pageNo, pageSize);

            // 终止条件：当前页无数据时退出循环
            if (CollUtils.isEmpty(boardList)) {
                break;
            }

            // 4. 数据转换处理
            // 4.1 将排名(rank)转换为数据库主键ID（防止排名重复冲突）
            boardList.forEach(b -> {
                b.setId(b.getRank().longValue());  // 例如：第1名ID=1，第2名ID=2
                b.setRank(null); // 清空临时排名字段（避免数据冗余）
            });

            // 4.2 批量持久化到数据库
            pointsBoardService.saveBatch(boardList); // MyBatisPlus批量保存

            // 5. 翻页处理（类似翻书动作）
//            pageNo++;
            pageNo += total;
        }

        // ==================== 阶段3：清理工作 ====================
        TableInfoContext.remove(); // 必须移除线程变量（防止内存泄漏）
    }

    @XxlJob("clearPointsBoardFromRedis")
    public void clearPointsBoardFromRedis(){
        // 1.获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        // 2.计算key
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + time.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);
        // 3.删除
        redisTemplate.unlink(key);
    }


}
